package com.cyh;

import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.apache.http.HttpEntity;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * @author CYH
 * @date 2020-01-07
 */
@Slf4j
public class MyHttpClient2 {

    private static volatile Integer successNum = 0;
    private static volatile Integer failedNum = 0;
    private static ExecutorService executorService;

    public static void main(String[] args) {
        try {
            cyh(args);
        } catch (Throwable e) {
            log.error("CYH_ERROR", e);
        }
    }

    private static void cyh(String[] args) {
        ArgumentData argData = parseArgs(args);
        executorService = Executors.newFixedThreadPool(argData.getThreadCount());
        CloseableHttpClient httpClient = initHttpClient(argData);

        String template = "http://localhost:38088/user/getSessionInfoBySessionId?sessionId=%s&app=music";

        for (int tc = 0; tc < argData.threadCount; tc++) {
            executorService.submit(() -> {
                String sessionId;
                HttpUriRequest request;
                CloseableHttpResponse response;
                HttpEntity entity;
                String result;
                for (int lt = 0; lt < argData.getLoopTimes(); lt++) {
                    try {
                        sessionId = (lt & 1) == 0 ? ("cyh_" + lt) : ("NeedCache_cyh_" + lt);
                        request = new HttpGet(String.format(template, sessionId));
                        response = httpClient.execute(request);
                        entity = response.getEntity();
                        result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                        log.info("result====={}", result);
                        successNum++;
                    } catch (Exception e) {
                        failedNum++;
                        log.warn("CYH_Exception", e);
                    } finally {
                        log.info("successNum={}, failedNum={}", successNum, failedNum);
                    }
                }
            });
        }
        log.warn("successNum={}, failedNum={}", successNum, failedNum);
        executorService.shutdown();
    }

    private static CloseableHttpClient initHttpClient(ArgumentData argData) {
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(1, TimeUnit.MINUTES);
        cm.setMaxTotal(argData.getMaxTotal());
        cm.setDefaultMaxPerRoute(argData.getMaxPerRoute());

        HttpRequestRetryHandler retryHandler = (e, executionCount, context) -> false;

        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(1000).setSocketTimeout(5000)
                .setConnectTimeout(1000).build();

        return HttpClients.custom().setDefaultRequestConfig(requestConfig).setConnectionManager(cm)
                .setRetryHandler(retryHandler).build();
    }

    private static ArgumentData parseArgs(String[] args) {
        ArgumentData data = new ArgumentData();
        if (Objects.nonNull(args)) {
            for (String x : args) {
                if (x.startsWith("threadCount")) {
                    data.threadCount = Integer.parseInt(x.split("=")[1]);
                } else if (x.startsWith("loopTimes")) {
                    data.loopTimes = Integer.parseInt(x.split("=")[1]);
                } else if (x.startsWith("maxTotal")) {
                    data.maxTotal = Integer.parseInt(x.split("=")[1]);
                } else if (x.startsWith("maxPerRoute")) {
                    data.maxPerRoute = Integer.parseInt(x.split("=")[1]);
                }
            }
        }
        return data;
    }

    @Data
    static class ArgumentData {
        Integer threadCount = 10;
        Integer loopTimes = 100;
        Integer maxTotal = 8192;
        Integer maxPerRoute = 1024;
    }

}
